open Graph
 
let debug = true

let (|>) x y = y x

(* We use Unit type for edges to solve a problem with unmatched signatures *)
(* in Dot.Parse second argument's edge function *)
module Unit = struct
	type t = unit
	let compare _ _ = 0 
	let default = ()
end 
(* we'll use true in snd argument to mark clique's member *)
module StrBool = struct
  type t = string * bool
end
module G = Persistent.Graph.AbstractLabeled(StrBool)(Unit)

(* Dot format input/output *)
module B = Builder.P(G)
module DotInput = 
  Dot.Parse
    (B)
    (struct 
      let node (id,_) _ = match id with
	| Dot_ast.Ident s
	| Dot_ast.Number s
	| Dot_ast.String s
	| Dot_ast.Html s -> (s,false)
      let edge _ = ()
    end)

module Display = struct
  include G
  let vertex_name v = String.escaped (V.label v |> fst)
  let graph_attributes _ = []
  let default_vertex_attributes _ = []
  let vertex_attributes v = 
		if G.V.label v |> snd 
		then [`Label "clique's member"; `Shape `Box] else [`Label ""; `Shape `Circle]
  let default_edge_attributes _ = []
  let edge_attributes _ = []
  let get_subgraph _ = None
end
module DotOutput = Graphviz.Neato(Display)

open Clique
module C = Clique(G)

open Timer
module T = Timer

(*open Dumper*)

let debugExecFunction func input name =
	let (maxclique, cliquesnum), time = 
		let now = T.now() in
		T.calc_exec_time (func input) now in
		
	Printf.printf "\n%s:\n" name;
	Printf.printf "Exec time: %f\n" time;
	Printf.printf "Total cliques found: %i\n" cliquesnum;
	Printf.printf "Time per clique: %f\n" (time /. float_of_int cliquesnum);
	(*print_endline (dump maxclique);*)
	flush_all()

let () =  
	try 
		
		if debug then 
			(print_string "Reading input file...\n"; flush_all());
		
		let input = DotInput.parse Sys.argv.(1) in
		
		if debug 
		then (
			print_string "Start clique finding...\n"; 
			flush_all();
		
			debugExecFunction C.ClassicBronKerbosch.maxclique_default input "Classic Bron-Kerbosch";
			debugExecFunction C.ClassicBronKerbosch.maxclique_heuristic input "CBK with heuristic choose function";
				
			debugExecFunction C.Johnston.maxclique_basic_method input "Basic Johnston method";
			debugExecFunction C.Johnston.maxclique_simplified_bk_method input "Simplified BK Johnston method";
		) else (
			let maxclique, cliquesnum = C.Johnston.maxclique_simplified_bk_method input in
			try
				let oc = open_out Sys.argv.(2) in
				(* copy edges to output graph without changes *)
				(* we can add some labels for edges here *)
				G.fold_edges (fun v1 v2 g -> G.add_edge g v1 v2) input G.empty 
					(* copy vertices with labels for clique members *)
					|> G.fold_vertex 
							(fun v g -> 
								if maxclique |> C.N.Vertex_Set.elements |> List.mem v 
								then G.V.create (G.V.label v |> fst,true) |> G.add_vertex g
								else G.add_vertex g v) 
							input 
					|> DotOutput.output_graph oc;
			  close_out oc; 
			with Invalid_argument _ -> 
				Printf.printf 
					"Total cliques found: %i\nMaximal clique size: %i\n" 
					cliquesnum
					(maxclique |> C.N.Vertex_Set.elements |> List.length)
		)
	with 
		| Invalid_argument _ -> print_string "Please, specify the input file."
		| Sys_error s -> print_string s; 
		| Failure s -> print_string ("Incorrect file format. " ^ s);

